home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Nebula 1
/
Nebula One.iso
/
Mail
/
pine3.92
/
pico
/
search.c
< prev
next >
Wrap
C/C++ Source or Header
|
1996-03-14
|
11KB
|
410 lines
#if !defined(lint) && !defined(DOS)
static char rcsid[] = "$Id: search.c,v 4.11 1996/03/15 07:41:11 hubert Exp $";
#endif
/*
* Program: Searching routines
*
*
* Michael Seibel
* Networks and Distributed Computing
* Computing and Communications
* University of Washington
* Administration Builiding, AG-44
* Seattle, Washington, 98195, USA
* Internet: mikes@cac.washington.edu
*
* Please address all bugs and comments to "pine-bugs@cac.washington.edu"
*
*
* Pine and Pico are registered trademarks of the University of Washington.
* No commercial use of these trademarks may be made without prior written
* permission of the University of Washington.
*
* Pine, Pico, and Pilot software and its included text are Copyright
* 1989-1996 by the University of Washington.
*
* The full text of our legal notices is contained in the file called
* CPYRIGHT, included with this distribution.
*
*/
/*
* The functions in this file implement commands that search in the forward
* and backward directions. There are no special characters in the search
* strings. Probably should have a regular expression search, or something
* like that.
*
*/
#include <stdio.h>
#include "osdep.h"
#include "pico.h"
#include "estruct.h"
#include "edef.h"
#ifdef ANSI
int eq(int, int);
int expandp(char *, char *, int);
#else
int eq();
int expandp();
#endif
/*
* Search forward. Get a search string from the user, and search, beginning at
* ".", for the string. If found, reset the "." to be just after the match
* string, and [perhaps] repaint the display. Bound to "C-S".
*/
/* string search input parameters */
#define PTBEG 1 /* leave the point at the begining on search */
#define PTEND 2 /* leave the point at the end on search */
static char *SearchHelpText[] = {
"Help for Search Command",
" ",
"\tEnter the words or characters you would like to search",
"~\tfor, then press ~R~e~t~u~r~n. The search then takes place.",
"\tWhen the characters or words that you entered ",
"\tare found, the buffer will be redisplayed with the cursor ",
"\tat the beginning of the selected text.",
" ",
"\tThe most recent string for which a search was made is",
"\tdisplayed in the \"Search\" prompt between the square",
"\tbrackets. This string is the default search prompt.",
"~ Hitting only ~R~e~t~u~r~n or at the prompt will cause the",
"\tsearch to be made with the default value.",
" ",
"\tThe text search is not case sensitive, and will examine the",
"\tentire message.",
" ",
"\tShould the search fail, a message will be displayed.",
" ",
"End of Search Help.",
" ",
NULL
};
/*
* Compare two characters. The "bc" comes from the buffer. It has it's case
* folded out. The "pc" is from the pattern.
*/
eq(bc, pc)
int bc;
int pc;
{
if ((curwp->w_bufp->b_mode & MDEXACT) == 0){
if (bc>='a' && bc<='z')
bc -= 0x20;
if (pc>='a' && pc<='z')
pc -= 0x20;
}
return(bc == pc);
}
forwsearch(f, n)
{
register int status;
int wrapt = FALSE;
char show[512];
/* resolve the repeat count */
if (n == 0)
n = 1;
if (n < 1) /* search backwards */
return(0);
/* ask the user for the text of a pattern */
while(1){
if ((status = readpattern("Search")) == TRUE){
break;
}
else{
switch(status){
case HELPCH: /* help requested */
if(Pmaster)
(*Pmaster->helper)(Pmaster->search_help,
"Help for Searching", 1);
else
pico_help(SearchHelpText, "Help for Searching", 1);
case (CTRL|'L'): /* redraw requested */
refresh(FALSE, 1);
update();
break;
case (CTRL|'V'):
gotoeob(0, 1);
mlerase();
curwp->w_flag |= WFMODE;
return(TRUE);
case (CTRL|'Y'):
gotobob(0, 1);
mlerase();
curwp->w_flag |= WFMODE;
return(TRUE);
default:
curwp->w_flag |= WFMODE;
if(status == ABORT)
emlwrite("Search Cancelled", NULL);
else
mlerase();
return(FALSE);
}
}
}
curwp->w_flag |= WFMODE;
/*
* This code is kind of dumb. What I want is successive C-W 's to
* move dot to successive occurences of the pattern. So, if dot is
* already sitting at the beginning of the pattern, then we'll move
* forward a char before beginning the search. We'll let the
* automatic wrapping handle putting the dot back in the right
* place...
*/
status = 0; /* using "status" as int temporarily! */
while(1){
if(pat[status] == '\0'){
forwchar(0, 1);
break; /* find next occurance! */
}
if(status + curwp->w_doto >= llength(curwp->w_dotp) ||
!eq(pat[status],lgetc(curwp->w_dotp, curwp->w_doto + status).c))
break; /* do nothing! */
status++;
}
/* search for the pattern */
while (n-- > 0) {
if((status = forscan(&wrapt,&pat[0],PTBEG)) == FALSE)
break;
}
/* and complain if not there */
if (status == FALSE){
expandp(&pat[0], &show[0], 50);
emlwrite("\"%s\" not found", show);
}
else if(wrapt == TRUE){
emlwrite("Search Wrapped");
}
else if(status == TRUE)
emlwrite("");
return(status);
}
/*
* Read a pattern. Stash it in the external variable "pat". The "pat" is not
* updated if the user types in an empty line. If the user typed an empty line,
* and there is no old pattern, it is an error. Display the old pattern, in the
* style of Jeff Lomicka. There is some do-it-yourself control expansion.
* change to using <ESC> to delemit the end-of-pattern to allow <NL>s in
* the search string.
*/
readpattern(prompt)
char *prompt;
{
register int s;
char tpat[NPAT+20];
EXTRAKEYS menu_pat[3];
menu_pat[0].name = "^Y";
menu_pat[0].label = "FirstLine";
menu_pat[0].key = (CTRL|'Y');
KS_OSDATASET(&menu_pat[0], KS_NONE);
menu_pat[1].name = "^V";
menu_pat[1].label = "LastLine";
menu_pat[1].key = (CTRL|'V');
KS_OSDATASET(&menu_pat[1], KS_NONE);
menu_pat[2].name = NULL;
strcpy(tpat, prompt); /* copy prompt to output string */
if(pat[0] != '\0'){
strcat(tpat, " ["); /* build new prompt string */
expandp(&pat[0], &tpat[strlen(tpat)], NPAT/2); /* add old pattern */
strcat(tpat, "]");
}
strcat(tpat, " : ");
s = mlreplyd(tpat, tpat, NPAT, QNORML, menu_pat);
if (s == TRUE) /* Specified */
strcpy(pat, tpat);
else if (s == FALSE && pat[0] != 0) /* CR, but old one */
s = TRUE;
return(s);
}
forscan(wrapt,patrn,leavep) /* search forward for a <patrn> */
int *wrapt; /* boolean indicating search wrapped */
char *patrn; /* string to scan for */
int leavep; /* place to leave point
PTBEG = begining of match
PTEND = at end of match */
{
register LINE *curline; /* current line during scan */
register int curoff; /* position within current line */
register LINE *lastline; /* last line position during scan */
register int lastoff; /* position within last line */
register int c; /* character at current position */
register LINE *matchline; /* current line during matching */
register int matchoff; /* position in matching line */
register char *patptr; /* pointer into pattern */
register int stopoff; /* offset to stop search */
register LINE *stopline; /* line to stop search */
*wrapt = FALSE;
/*
* the idea is to set the character to end the search at the
* next character in the buffer. thus, let the search wrap
* completely around the buffer.
*
* first, test to see if we are at the end of the line,
* otherwise start searching on the next character.
*/
if(curwp->w_doto == llength(curwp->w_dotp)){
/*
* dot is not on end of a line
* start at 0 offset of the next line
*/
stopoff = curoff = 0;
stopline = curline = lforw(curwp->w_dotp);
if (curwp->w_dotp == curbp->b_linep)
*wrapt = TRUE;
}
else{
stopoff = curoff = curwp->w_doto;
stopline = curline = curwp->w_dotp;
}
/* scan each character until we hit the head link record */
/*
* maybe wrapping is a good idea
*/
while (curline){
if (curline == curbp->b_linep)
*wrapt = TRUE;
/* save the current position in case we need to
restore it on a match */
lastline = curline;
lastoff = curoff;
/* get the current character resolving EOLs */
if (curoff == llength(curline)) { /* if at EOL */
curline = lforw(curline); /* skip to next line */
curoff = 0;
c = '\n'; /* and return a <NL> */
} else
c = lgetc(curline, curoff++).c; /* get the char */
/* test it against first char in pattern */
if (eq(c, patrn[0]) != FALSE) { /* if we find it..*/
/* setup match pointers */
matchline = curline;
matchoff = curoff;
patptr = &patrn[0];
/* scan through patrn for a match */
while (*++patptr != 0) {
/* advance all the pointers */
if (matchoff == llength(matchline)) {
/* advance past EOL */
matchline = lforw(matchline);
matchoff = 0;
c = '\n';
} else
c = lgetc(matchline, matchoff++).c;
/* and test it against the pattern */
if (eq(*patptr, c) == FALSE)
goto fail;
}
/* A SUCCESSFULL MATCH!!! */
/* reset the global "." pointers */
if (leavep == PTEND) { /* at end of string */
curwp->w_dotp = matchline;
curwp->w_doto = matchoff;
} else { /* at begining of string */
curwp->w_dotp = lastline;
curwp->w_doto = lastoff;
}
curwp->w_flag |= WFMOVE; /* flag that we have moved */
return(TRUE);
}
fail:; /* continue to search */
if((curline == stopline) && (curoff == stopoff))
break; /* searched everywhere... */
}
/* we could not find a match */
return(FALSE);
}
/* expandp: expand control key sequences for output */
expandp(srcstr, deststr, maxlength)
char *srcstr; /* string to expand */
char *deststr; /* destination of expanded string */
int maxlength; /* maximum chars in destination */
{
char c; /* current char to translate */
/* scan through the string */
while ((c = *srcstr++) != 0) {
if (c == '\n') { /* its an EOL */
*deststr++ = '<';
*deststr++ = 'N';
*deststr++ = 'L';
*deststr++ = '>';
maxlength -= 4;
} else if (c < 0x20 || c == 0x7f) { /* control character */
*deststr++ = '^';
*deststr++ = c ^ 0x40;
maxlength -= 2;
} else if (c == '%') {
*deststr++ = '%';
*deststr++ = '%';
maxlength -= 2;
} else { /* any other character */
*deststr++ = c;
maxlength--;
}
/* check for maxlength */
if (maxlength < 4) {
*deststr++ = '$';
*deststr = '\0';
return(FALSE);
}
}
*deststr = '\0';
return(TRUE);
}